/************************************************************************

								Heroes IV
					  Copyright 2001, The 3DO Company

	------------------------------------------------------------------
  						 combat_ai.h

	$Header: $

	$NoKeywords: $

 ************************************************************************/

#if !defined( COMBAT_AI_H_INCLUDED )
#define COMBAT_AI_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


#include "ai_combat_data_cache.h"
#include "battlefield.h"
#include "combat_ai_action_ptr.h"
#include "counted_ptr.h"

class t_combat_creature;
class t_area_effect_point;

class t_combat_ai
{
public:
	t_combat_ai(t_combat_creature &actor);

	t_combat_ai_action_ptr get_best_action(void);

	void						consider_action( t_abstract_combat_ai_action* action );
	t_combat_creature &			get_actor(void);
	const t_combat_creature &	get_actor(void) const;

	// Low level weighing, utility functions for AI
	static double get_zoc_change_weight( int damage, const t_combat_creature &target, 
										 bool turn, int new_angle);
	static double would_interfere(  const t_combat_creature &interferer, 
									const t_combat_creature &interferee, 
								    int interferer_facing, bool post_attack);

private:
	bool					area_effect_point_is_better( const t_area_effect_point &p1, 
														 const t_area_effect_point &p2) const;
	t_combat_ai_action_ptr	get_best_of_list(t_combat_ai_action_list &list);
	void					generate_ranged(void);		// Put ranged actions in list (if available)
	void					generate_spell(void);		// Put spell actions in list (if available)

	t_combat_creature &		m_actor; // Unit we are deciding an action for
	t_combat_ai_action_ptr	m_best_action;
};


inline
t_combat_creature & t_combat_ai::get_actor(void)
{
	return m_actor;
}

inline
const t_combat_creature & t_combat_ai::get_actor(void) const
{
	return m_actor;
}

// Return enemy_combat_value / friendly_combat_value, capped to 10.0 to 0.1
inline double get_friendly_weighing_factor(double friendly_combat_value, double enemy_combat_value)
{
	if (friendly_combat_value == 0.0)
		return 0.0;
	
	double factor = enemy_combat_value / friendly_combat_value;

	if (factor < 0.2)
		return 0.2;
	if (factor > 3.0) // above this, we're doomed, so healing, etc. is a waste of time.
		return 0.0;
	return factor;
}

inline bool spellcasting_is_worthwhile( t_battlefield& battlefield, bool side )
{
	return battlefield.get_data_cache().spellcasting_is_worthwhile( side );
}

inline int get_approximate_lifespan( t_battlefield& battlefield, t_combat_creature const& target )
{
	return battlefield.get_data_cache().get_approximate_lifespan( target );
}

// Get the friendly-effect weighing factor (known in the design document
// as the beneficial spell weighing factor) for the current actor. All
// weights which come from impacting friendly units should be multiplied 
// by this factor. 
inline double get_friendly_weighing_factor( t_battlefield& battlefield, bool side ) 
{
	t_ai_combat_data_cache &cache = battlefield.get_data_cache();
	double					friendly_value = cache.get_total_combat_value( side );
	double					enemy_value = cache.get_total_combat_value( !side );

	return get_friendly_weighing_factor( friendly_value, enemy_value );
}

inline int get_approximate_battle_length( t_battlefield& battlefield )
{
	return battlefield.get_data_cache().get_approximate_battle_length();
}

bool ai_check_retreat( t_battlefield& battlefield );
bool threatens_enemies( t_combat_creature const& attacker );


#endif // COMBAT_AI_H_INCLUDED
